
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class CKeypadDisplay:

    def __init__(self,  infoWidget, valueWidget, descriptionWidget = None):

        self.infoWidget = infoWidget
        self.valueWidget = valueWidget
        self.descriptionWidget = descriptionWidget
        self.valueString = ''
        self.caret = -1
        self.flashOn = False


    def WriteInfo(self, content):
        self.infoWidget.setText(content)

    def WriteValue(self, value):
        self.valueString = value
        self.valueWidget.setText(value)

    def UpdateDescription(self, content):
        self.descriptionWidget.setText(content)




class CKeypad:

    def __init__(self,  display, protocol, dbFileName = None):

        self.display = display
        self.protocol = protocol

        self.statusState = 0
        self.paramViewState = 1
        self.paramEditState = 2
        self.messageState = 3

        self.state = self.statusState

        self.memMode = False
        self.active = False
        
        self.activeMenu = 0
        self.activeParam = 0
        self.activeValue = 0
        self.activeFormat = 0
        self.activeMin = 0
        self.activeMax = 100
        self.activeMaxParam = 255
        self.activeMessaage = ''

        self.statusParamAddr = 0
        self.statusValue = 0
        self.statusFormat = 0

        self.driveState = 0
        self.driveStateReady = 0
        self.driveStateRun = 1
        self.driveStateTrip = 2
        self.stateString = ['Ready', 'Run', 'Trip']
        self.unitString = ['', 'Hz', 'A','V', 'rpm', 'mps', '%']

        self.caretPos = -1
        self.displayCaret = -1

        self.prIndexMenu = 0
        self.prIndexParam = 1
        self.prIndexValue = 2
        self.prIndexMin = 3
        self.prIndexMax = 4
        self.prIndexDefault = 5
        self.prIndexUnit = 6
        self.prIndexDF = 7

        self.flashOn = False
        self.count = 0


    def Start(self):
        self.state = self.statusState
        self.GetCurrentStatusParam()


    def UpdateDisplay(self):

        self.count = self.count + 1
        if self.count > 5:
            self.flashOn  = not self.flashOn
            self.count = 0

        if self.state == self.statusState or self.state == self.messageState:
            error, value = self.protocol.Read(0x3300)
            
            statusWord = value[0]
            
            if (statusWord >> 8) != 0:
                self.driveState = self.driveStateTrip
                self.display.WriteValue('Err:%02x'%statusWord >> 8)
            else:
                if (statusWord & 0x01) == 0:
                    self.driveState = self.driveStateReady
                else:
                    self.driveState = self.driveStateRun

                self.GetActiveParamValue()
                self.display.WriteValue(self.GetActiveValueString())

            self.display.WriteInfo(self.stateString[self.driveState])


        elif self.state == self.paramViewState or self.state == self.paramEditState:
            if self.state == self.paramViewState:
                self.GetActiveParamValue()
            self.display.WriteInfo('F%02d.%03d'%(self.activeMenu, self.activeParam))

            self.display.WriteValue(self.GetActiveValueString())

    def GetActiveValueString(self):

        s = ''

        if self.state == self.statusState:
            value = self.statusValue
            format = self.statusFormat
        else:
            value = self.activeValue
            format = self.activeFormat

        unit = (format >> 6) & 0x07
        dp = (format >> 1) & 0x03
        type = format & 0x01


        if self.state == self.paramEditState and not self.flashOn:
            if type == 0:
                s = '% 10d'%value
                l = list(s)
                if l[len(l) - self.caretPos - 1] == ' ':
                    l[len(l) - self.caretPos - 1] = '_'
                else:
                    l[len(l) - self.caretPos - 1] = ' '
                if dp != 0:
                    l.insert(10-dp, '.')
                s = '%s%-4s'%(''.join(l), self.unitString[unit])
            else:
                s = '0x% 18x'%value
                l = list(s)
                if l[len(l) - self.caretPos - 1] == ' ':
                    l[len(l) - self.caretPos - 1] = '_'
                else:
                    l[len(l) - self.caretPos - 1] = ' '
                s = '%s%-4s'%(''.join(l), self.unitString[unit])

        else:
            if type == 0:
                s = '% *.*f%-4s'%(10-dp, dp, value/(10**dp), self.unitString[unit])
            else:
                s = '0x% 8x%-4s'%(value, self.unitString[unit])

        return s

    def EnterAction(self):

        if self.state == self.statusState:
            self.RequestToState(self.paramViewState)
        elif self.state == self.paramViewState:
            self.RequestToState(self.paramEditState)
        elif self.state == self.paramEditState:
            self.AcceptValue()
            self.RequestToState(self.paramViewState)


    def EscAction(self):

        if self.state == self.paramEditState :
            self.RequestToState(self.paramViewState)
        elif self.state == self.paramViewState:
            self.RequestToState(self.statusState)


    def LeftAction(self):

        if self.state == self.paramViewState:

            self.GetPrevMenu(self.activeMenu)

        elif self.state == self.paramEditState:

            self.caretPos = self.caretPos + 1
            if self.caretPos == 10:
                self.caretPos = 0

        #TODO: GetPrevStatusParam
        #elif self.state == self.statusState:
            #self.RequestToState(self.paramViewState)

    def RightAction(self):

        if self.state == self.paramViewState:

            self.GetNextMenu(self.activeMenu)

        elif self.state == self.paramEditState:

            self.caretPos = self.caretPos - 1
            if self.caretPos == -1:
                self.caretPos = 10

        elif self.state == self.statusState:
            self.GetNextStatusParam()


    def UpAction(self):

        if self.state == self.paramViewState:

            self.GetNextParam(self.activeParam)

        elif self.state == self.paramEditState:

            self.activeValue = self.activeValue + 10**self.caretPos

            if self.activeValue > self.activeMax:
                self.activeValue = self.activeMax

        elif self.state == self.statusState:
            self.RequestToState(self.paramViewState)

    def DownAction(self):

        if self.state == self.paramViewState:

            self.GetPrevParam(self.activeParam)

        elif self.state == self.paramEditState:

            self.activeValue = self.activeValue - 10**self.caretPos

            if self.activeValue < self.activeMin:
                self.activeValue = self.activeMin

        elif self.state == self.statusState:
            self.RequestToState(self.paramViewState)

    def RunAction(self, dir):
        
        cw = 0x00c7 +(dir << 3)
        self.protocol.WriteSingle(0x3200, cw)

    def StopAction(self, stopMode):
        cw = 0x02c6 - stopMode
        self.protocol.WriteSingle(0x3200, cw)

    def RunPressed(self):
        self.buttonState |= 1
        
    def RunReleased(self):
        self.buttonState &= 0xFFFE

    def StopPressed(self):
        self.buttonState |= 0x02
        
    def StopReleased(self):
        self.buttonState &= 0xFFFD



    def RequestToState(self, newState):


        if newState == self.statusState:
            self.state = newState
            self.GetCurrentStatusParam()
            self.GetActiveParamInfo()

        else:

            self.GetActiveParamInfo()

            if self.state == self.paramEditState:
                self.caretPos = -1
                self.displayCaret = -1
            else:
                self.caretPos = 0
                self.displayCaret = 0
                
            self.state = newState


    def AcceptValue(self):

        self.protocol.WriteSingle((self.activeMenu << 8) + self.activeParam, self.activeValue)

    def GetNextMenu(self, menu):
        
        error, value = self.protocol.GetNextMenu(menu)
        if error == 0:
            self.activeMenu = value
            self.activeParam = 0
            
        error, value = self.protocol.GetMaxParamInMenu(self.activeMenu)
        if error != 0:
            self.activeMaxParam = value
            
        self.GetActiveParamInfo()
        self.GetActiveParamValue()

    def GetPrevMenu(self, menu):
        
        error, value = self.protocol.GetPrevMenu(menu)
        if error == 0:
            self.activeMenu = value
            self.activeParam = 0

        error, value = self.protocol.GetMaxParamInMenu(self.activeMenu)
        if error != 0:
            self.activeMaxParam = value
            
        self.GetActiveParamInfo()
        self.GetActiveParamValue()
        
    def GetNextParam(self, param):
        
        param = param + 1
        if param > self.activeMaxParam:
            param = 0
        self.activeParam = param
        
        self.GetActiveParamInfo()
        
        
    def GetPrevParam(self, param):
        param = param - 1
        if param < 0:
            param = self.activeMaxParam
        self.activeParam = param
        
            
        self.GetActiveParamInfo()


    def GetCurrentStatusParam(self):
        
        error, value = self.protocol.GetCurrentStatusFuncIndex()
        
        if error == 0:
            self.statusParamAddr = value
        

    def GetNextStatusParam(self):
        
        error, value = self.protocol.GetNextStatusFuncIndex()
        
        if error == 0:
            self.statusParamAddr = value
        
    def GetActiveParamValue(self):
        
        if self.state == self.statusState:
            
            error, value = self.protocol.Read(self.statusParamAddr)
            
            if error == 0:
                self.statusValue = value[0]
        
        else:
            
            error, value = self.protocol.Read((self.activeMenu << 8) + self.activeParam)
            
            if error == 0:
                self.activeValue = value[0]
                
                
    def GetActiveParamInfo(self):
        
        if self.state == self.statusState:
            
            error, value = self.protocol.GetParamFormat(self.statusParamAddr >> 8, self.statusParamAddr & 0xFF)
            self.statusFormat = value
                
        
        else:
            
            error, value = self.protocol.GetParamFormat(self.activeMenu , self.activeParam)
            self.activeFormat = value
            error, value = self.protocol.GetParamRange(self.activeMenu , self.activeParam, 'min')
            self.activeMin = value
            error, value = self.protocol.GetParamRange(self.activeMenu , self.activeParam, 'max')
            self.activeMax = value
            error, value = self.protocol.GetParamDefault(self.activeMenu , self.activeParam)
            self.activeDefault = value
        
        
